// Copyright (c) 2024 刻BITTER
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.


#pragma once

#include <cstdint>
#include <cstdlib>

#include "./common.hpp"

namespace data_basic {

    namespace hide {
        template <typename IndexType, IndexType Max, bool NoSize>
        class SizeHelper {};


        template <typename IndexType, IndexType Max>
        class SizeHelper<IndexType, Max, true> {
           private:
           public:
            void inc() {}

            void dec() {}

            IndexType size() const {
                return Max;  // No size, always return Max
            }

            void set_size(IndexType size) {
                // No operation, as size is not tracked
            }
        };


        template <typename IndexType, IndexType Max>
        class SizeHelper<IndexType, Max, false> {
           private:
            IndexType _size = 0;

           public:
            void inc() {
                if (_size < Max)  // Ensure we do not exceed the maximum size
                    ++_size;
            }

            void dec() {
                if (_size > 0) {
                    --_size;
                }
            }

            IndexType size() const {
                return _size;
            }

            void set_size(IndexType size) {
                if (size > Max) {
                    _size = Max;  // Cap size to Max
                } else {
                    _size = size;
                }
            }
        };
    }  // namespace hide


    /**
     * @brief 精简的环形队列实现
     *
     * @tparam T 数据类型
     * @tparam N 数组长度
     */
    template <typename T, size_t N, bool NoSize = 0, typename _IndexType = enough_and_fast_index_type<N>>
    class RingBuffer {
       public:
        using IndexType = _IndexType;

       private:
        T _buf[N];
        IndexType _index_back = 0;
        IndexType _index_front = 0;
        hide::SizeHelper<IndexType, N, NoSize> _size_helper;

        constexpr IndexType _inc_index(IndexType i) {
            if (i == N - 1)
                return 0;

            return i + 1;
        }

        constexpr IndexType _dec_index(IndexType i) {
            if (i == 0)
                return N - 1;

            return i - 1;
        }

       public:
        bool empty() const {
            return size() == 0;
        }

        /**
         * @brief 填入缓冲区的数据个数
         *
         * @return IndexType
         */
        IndexType size() const {
            return _size_helper.size();
        }

        size_t max_size() const {
            return N;
        }

        /**
         * @brief 缓冲区是否已满
         *
         * @return false   填入的数据个数大于或等于缓冲区尺寸
         * @return true  可以继续安全的填入数据
         */
        bool not_full() const {
            return size() < N;
        }

        void clear() {
            _index_front = 0;
            _index_back = 0;
            _size_helper.set_size(0);
        }

        /**
         * @brief 尾部追加一个元素
         *
         * 当空间不足时将发生数据覆盖，此时会自动pop_front 删除最旧的一个数据。
         *
         * @param val
         */
        void push_back(T val) {
            _buf[_index_back] = val;
            _index_back = _inc_index(_index_back);
            
            if constexpr(!NoSize) {
                if(size() < N) {
                    _size_helper.inc();
                }
                else {
                    // 将要发生数据覆盖，挪动front 位置
                    _index_front = _inc_index(_index_front);
                }
            }
        }

        T pop_back() {
            _index_back = _dec_index(_index_back);
            _size_helper.dec();
            return _buf[_index_back];
        }

        T pop_front() {
            _size_helper.dec();
            T t = _buf[_index_front];
            _index_front = _inc_index(_index_front);
            return t;
        }

        /**
         * @brief 将一个数据重复填入缓冲区指定的次数
         *
         * @param val
         * @param count
         */
        void init(T val, size_t count) {
            // assert(count <= N, 'Max Size N Can Not Be Exceeded');
            while (count--) {
                push_back(val);
            }
        }

        T &back() {
            return _buf[_dec_index(_index_back)];
        }

        T &front() {
            return _buf[_index_front];
        }

        T back() const {
            return _buf[_dec_index(_index_back)];
        }

        T front() const {
            return _buf[_index_front];
        }

        IndexType front_index() const {
            return _index_front;
        }

        IndexType back_index() const {
            return _index_back;
        }

        T value(IndexType i) const {
            return _buf[i];
        }

        void set_value(IndexType i, T v) {
            _buf[i] = v;
        }

        IndexType inc_index(IndexType i) {
            return _inc_index(i);
        }

        IndexType dec_index(IndexType i) {
            return _dec_index(i);
        }
    };


    template <typename T, size_t N>
    using FixedRingBuffer = RingBuffer<T, N, true>;

}  // namespace data_basic
